#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <left4dhooks>

#define DMG_ACID_A 263168
#define DMG_ACID_B 265216

// 定义ConVar变量
ConVar g_cvHorizontalForce;
ConVar g_cvVerticalForce;

// Sound
#define EXPLOSION_SOUND "ambient/explosions/explode_1.wav"


public Plugin myinfo = 
{
	name 			= "l4d2_acid_knockback",
	author 			= "豆瓣酱な",
	description 	= "Spitter吐的痰击飞玩家",
	version 		= "1.0",
	url 			= "https://gitee.com/sweet-and-sour-bombs/adfvsdsd"
}


public void OnPluginStart()
{
	// 注册ConVar变量
	g_cvHorizontalForce = CreateConVar("sm_acid_horizontal", "150.0", "水平击飞力度", FCVAR_NOTIFY, true, 100.0, true, 2000.0);
    
	g_cvVerticalForce = CreateConVar("sm_acid_vertical", "251.0", "垂直击飞力度", FCVAR_NOTIFY, true, 100.0, true, 2000.0);
    

	// 自动生成配置文件
	//AutoExecConfig(true, "l4d2_acid_knockback");
    
	// 挂钩伤害事件
	for (int i = 1; i <= MaxClients; i++)
	{
		if (IsClientInGame(i))
		{
			SDKHook(i, SDKHook_OnTakeDamage, OnTakeDamage);
		}
	}
}

public void OnMapStart()
{
    // 预缓存音效
	PrecacheSound(EXPLOSION_SOUND);
}

public void OnClientPutInServer(int client)
{
	SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
}

public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon,float damageForce[3], float damagePosition[3])
{
	// 仅处理酸液伤害
	if (damagetype != DMG_ACID_A && damagetype != DMG_ACID_B)
	{
		return Plugin_Continue;
	}

	if (IsClientPinned(victim) || IsPlayerIncapacitated(victim) || IsPlayerHanging(victim))
	{
		return Plugin_Continue;
	}

	/* ---- 动态获取ConVar参数 ---- */
	float hForce = g_cvHorizontalForce.FloatValue;
	float vForce = g_cvVerticalForce.FloatValue;


	/* ---- 物理计算 ---- */
	float HeadingVector[3], resulting[3], fPos[3];
    
	// 获取受害者视角方向
	GetClientEyeAngles(victim, HeadingVector);
    
	// 获取当前速度
	GetEntPropVector(victim, Prop_Data, "m_vecVelocity", resulting);
    
	// 计算方向分量
	resulting[0] =- Cosine(DegToRad(HeadingVector[1])) * hForce;
	resulting[1] =- Sine(DegToRad(HeadingVector[1])) * hForce;
	resulting[2] = vForce;
    
	// 应用效果
	TeleportEntity(victim, NULL_VECTOR, NULL_VECTOR, resulting);
	GetClientAbsOrigin(victim, fPos);
	L4D_StaggerPlayer(victim, victim, fPos);
	L4D2_CTerrorPlayer_Fling(victim, victim, resulting);

	// 播放爆炸音效（在玩家位置）
	EmitSoundToAll(EXPLOSION_SOUND, victim, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0);

	return Plugin_Changed;
}

//判断玩家是否被控
bool IsClientPinned(int client)
{
	// 检查玩家有效性
	if(!IsValidClient(client))
		return false;

	if (GetEntPropEnt(client, Prop_Send, "m_pummelAttacker") > 0)
		return true;
	if (GetEntPropEnt(client, Prop_Send, "m_carryAttacker") > 0)
		return true;
	if (GetEntPropEnt(client, Prop_Send, "m_pounceAttacker") > 0)
		return true;
	if (GetEntPropEnt(client, Prop_Send, "m_jockeyAttacker") > 0)
		return true;
	if (GetEntPropEnt(client, Prop_Send, "m_tongueOwner") > 0)
		return true;
	return false;
}

// 判断玩家是否倒地
bool IsPlayerIncapacitated(int client)
{
	// 检查玩家有效性
	if(!IsValidClient(client))
		return false;
    
	// 使用Prop_Send获取倒地状态
	return GetEntProp(client, Prop_Send, "m_isIncapacitated") != 0;
}

// 判断玩家是否挂边
bool IsPlayerHanging(int client)
{
	// 检查玩家有效性
	if(!IsValidClient(client))
	return false;
    
	// 使用Prop_Send获取挂边状态
	return GetEntProp(client, Prop_Send, "m_isHangingFromLedge") != 0;
}


//判断是否有效玩家
bool IsValidClient(int client)
{
	return client > 0 && IsClientInGame(client) && IsPlayerAlive(client)&& GetClientTeam(client) == 2;
}


